package com.sntk.organauthomanager.application.service;

import com.sntk.organauthomanager.application.dto.*;
import com.sntk.organauthomanager.domain.model.*;
import com.sntk.organauthomanager.domain.repository.*;
import com.sntk.organauthomanager.infrastructure.commit.HisUserCommit;
import com.sntk.organauthomanager.infrastructure.exception.DataNoLegalException;
import com.sntk.organauthomanager.infrastructure.exception.ObjectDisbaledException;
import com.sntk.organauthomanager.infrastructure.exception.ObjectNotFoundException;
import com.sntk.organauthomanager.infrastructure.utils.ChineseCharacterUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @ClassName: UserApplicationService
 * @author: wgchao
 * @createTime: 2020/7/21 8:51 AM
 * @Description: TODO
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class UserApplicationService {
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private OrganizationRepository organizationRepository;
    @Autowired
    private RoleRepository roleRepository;
    @Autowired
    private UserRoleRepository userRoleRepository;
    @Autowired
    private UserAffiliateRepository userAffiliateRepository;
    @Autowired
    private ResourceRepository resourceRepository;
    @Autowired
    private UserResourceRepository userResourceRepository;
    @Autowired
    private ApplicationEventPublisher publisher;

    private HisUserCommit hisUserCommit;

    /**
     * 添加用户
     * @param creator
     * @param operator
     */
    public void addUserToOrgan(UserCreator creator, String operator){
        Organization organization = organizationRepository.findByKey(creator.getInstitutionNumber());
        if(organization == null){
            throw new ObjectNotFoundException("所属机构不存在");
        }

        //密码强度检测
        if(!new PasswordIntensityDetectionService().intensityDetection(creator.getPassword())){
            throw new DataNoLegalException("密码强度不够，至少8个字符，至少1个大写字母，1个小写字母和1个数字,不能包含特殊字符");
        }

        //密码加密
        String encodePwd = userRepository.encodePassword(creator.getPassword());

        //TODO 如果没有HIS编码 需要在HIS中创建
//        if(StringUtils.isEmpty(creator.getHisCode())){
//            creator.setHisCode(hisUserCommit.createHisUser(organization.getHisInstitutionNumber(), creator.getUserName()));
//        }

        User user = organization.addUser(creator.getUname(), encodePwd, creator.getUserName(), creator.getHisCode(), creator.getHisDepartmentCode(),
                StringUtils.isEmpty(creator.getShorthandCode())?ChineseCharacterUtil.getLowerCase(creator.getUserName(), false):creator.getShorthandCode(),
                creator.getPhoneNumber(),
                creator.getRemark(), creator.getUserType());
        userRepository.add(user, operator);
    }

    /**
     * 修改用户信息
     * @param userDTO
     * @param operator
     */
    public void modifyUserInfo(UserDTO userDTO, String operator){
        User user = userRepository.findByKey(userDTO.getUname());
        if(user == null){
            throw new ObjectNotFoundException("用户不存在");
        }
        user.modifyUserInfo(userDTO.getUserName(), userDTO.getHisCode(), userDTO.getHisDepartmentCode(),
                StringUtils.isEmpty(userDTO.getShorthandCode())?ChineseCharacterUtil.getLowerCase(userDTO.getUserName(), false):userDTO.getShorthandCode(),
                userDTO.getPhoneNumber(),
                userDTO.getRemark(), userDTO.getDisabled(), userDTO.getUserType());
        userRepository.add(user, operator);
    }

    /**
     * 删除用户
     * @param uname
     * @param operator
     */
    public void removeUser(String uname, String operator){
        User user = userRepository.findByKey(uname);
        if(user == null){
            throw new ObjectNotFoundException("用户不存在");
        }
        userRepository.delete(uname, operator);

        //发送事件
        publisher.publishEvent(new UserRemovedEvent(uname, new Date(), operator));
    }

    /**
     * 管理员重置用户密码
     */
    public void resetPassword(String uname, String newpwd, OperatorInfo operatorInfo){
        if(!operatorInfo.isAdmin()){
            throw new DataNoLegalException("您的账户不是管理员账户");
        }
        User user = userRepository.findByKey(uname);
        if(user == null){
            throw new ObjectNotFoundException("用户不存在");
        }
        //密码强度检测
        if(!new PasswordIntensityDetectionService().intensityDetection(newpwd)){
            throw new DataNoLegalException("密码强度不够，至少8个字符，至少1个大写字母，1个小写字母和1个数字,不能包含特殊字符");
        }
        //密码加密
        String encodePwd = userRepository.encodePassword(newpwd);
        user.modifyPassword(encodePwd);
        userRepository.add(user, operatorInfo.getOperator());
    }

    /**
     * 账户修改自己的密码
     * @param userPwd
     * @param operatorInfo
     */
    public void modifyOwnPassword(UserPwd userPwd, OperatorInfo operatorInfo){
        User user = userRepository.findByKey(operatorInfo.getOperator());
        if(user == null){
            throw new ObjectNotFoundException("用户不存在");
        }
        if(!userRepository.matchPassword(userPwd.getOldPwd(), user.getPassword())){
            throw new ObjectDisbaledException("原密码错误");
        }
        user.modifyPassword(userRepository.encodePassword(userPwd.getNewPwd()));
        userRepository.add(user, operatorInfo.getOperator());
    }

    /**
     * 为用户分配角色
     * @param uname
     * @param roleCodes
     */
    public void assignRolesToUser(String uname, List<String> roleCodes, String operator){
        User user = userRepository.findByKey(uname);
        if(user == null){
            throw new ObjectNotFoundException("用户不存在");
        }
        Organization organization = organizationRepository.findByKey(user.getInstitutionNumber());
        if(organization == null){
            throw new ObjectNotFoundException("用户所在机构不存在");
        }
        List<Role> roles = null;
        if(roleCodes!=null && !roleCodes.isEmpty()){
            roles = new ArrayList<>();
            for(String roleCode : roleCodes){
                Role role = roleRepository.findByKey(new RoleIdentify(user.getInstitutionNumber(), roleCode));
                if(role == null){
                    throw new ObjectNotFoundException("分配角色不存在");
                }
                roles.add(role);
            }
        }
        UserRole userRole = new assignRolesToUserService().assign(organization, user, roles);
        userRoleRepository.add(userRole, operator);
    }

    /**
     * 用户删除-删除用户角色关系
     * @param userRemovedEvent
     */
    @EventListener
    public void removeUserRole(UserRemovedEvent userRemovedEvent){
        userRoleRepository.removeByUser(userRemovedEvent.getUname(), userRemovedEvent.getOperator());
    }

    /**
     * 角色删除-删除用户角色关系
     * @param roleRemovedEvent
     */
    @EventListener
    public void removeUserRole(RoleRemovedEvent roleRemovedEvent){
        userRoleRepository.removeByRole(new RoleIdentify(roleRemovedEvent.getInstitutionNumber(), roleRemovedEvent.getRoleCode()),
                roleRemovedEvent.getOperator());
    }

    //关联机构
    public void affiliate(String uname, List<AffiliateInfoDTO> affiliateInfoDTOS, String operator){
        User user = userRepository.findByKey(uname);
        if(user == null){
            throw new ObjectNotFoundException("用户不存在");
        }
        List<AffiliateInfo> affiliateInfos = new ArrayList<>();
        if(affiliateInfoDTOS!=null && !affiliateInfoDTOS.isEmpty()){
            for(AffiliateInfoDTO affiliateInfoDTO : affiliateInfoDTOS){
                Organization organization = organizationRepository.findByKey(affiliateInfoDTO.getInstitutionNumber());
                if(organization == null){
                    throw new ObjectNotFoundException("机构不存在");
                }
                affiliateInfos.add(new AffiliateInfo(organization, affiliateInfoDTO.getHisCode()));
            }
        }
        UserAffiliate userAffiliate = new AssignUserAffiliateService().assignUserAffiliate(user, affiliateInfos);
        userAffiliateRepository.add(userAffiliate, operator);

        //发布事件
        publisher.publishEvent(new UserAffiliateChangedEvent(user, userAffiliate, operator, new Date()));
    }


    //用户删除-删除用户私有权限
    @EventListener
    public void removeUserResources(UserRemovedEvent userRemovedEvent){
        userResourceRepository.deleteAllOfUser(userRemovedEvent.getUname(), userRemovedEvent.getOperator());
    }

    @EventListener
    public void removeUserResources(UserAffiliateChangedEvent userAffiliateChangedEvent){
        //获取用户机构列表
        List<String> organs = new ArrayList<>();
        organs.add(userAffiliateChangedEvent.getUser().getInstitutionNumber());
        if(userAffiliateChangedEvent.getUserAffiliate()!=null && userAffiliateChangedEvent.getUserAffiliate().getAffiliates()!=null){
            userAffiliateChangedEvent.getUserAffiliate().getAffiliates().stream().forEach(affiliateInfo -> {
                organs.add(affiliateInfo.getInstitutionNumber());
            });
        }
        userResourceRepository.deleteAllOfUserNotInOrgan(userAffiliateChangedEvent.getUser().getUname(),
                organs, userAffiliateChangedEvent.getOperator());
    }

    /**
     * 为用户分配独有资源权限
     * @param resourcesUser
     * @param operatorInfo
     * @return
     */
    public void assignResourcesToUser(ResourcesUser resourcesUser, OperatorInfo operatorInfo) {

        User user = userRepository.findByKey(resourcesUser.getUname());
        if(ObjectUtils.isEmpty(user)){
            throw new ObjectNotFoundException("用户不存在");
        }
        user.normalException();

        Organization organization = organizationRepository.findByKey(resourcesUser.getInstitutionNumber());
        if(organization == null){
            throw new ObjectNotFoundException("机构不存在");
        }
        organization.normalException();

        UserAffiliate userAffiliate = userAffiliateRepository.findByKey(user.getUname());


        List<Resource> resources = new ArrayList<>();
        if(!ObjectUtils.isEmpty(resourcesUser.getMarks())){
            for(String mark : resourcesUser.getMarks()){
                Resource resource = resourceRepository.findByKey(mark);
                if(resource == null){
                    throw new ObjectNotFoundException("分配资源不存在");
                }
                resources.add(resource);
            }
        }
        UserResource userResource = new AssignResourcesToUserService().assign(user, userAffiliate, organization, resources);
        userResourceRepository.add(userResource, operatorInfo.getOperator());
    }
}
